/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.nanosn.coffeemaker.databaseproject;

import com.nanosn.coffeemaker.Application;
import com.nanosn.coffeemaker.Settings;
import com.nanosn.coffeemaker.freemarker.FMPP;
import com.nanosn.coffeemaker.userinput.Models;
import com.nanosn.utils.FileUtility;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * TODEV: Generate the Entity Test files.
 * This class is responsible for generating the database project and initial
 * source files
 * @author selkhateeb
 */
public class ProjectGenerator
{
    // <editor-fold defaultstate="collapsed" desc="Private Fields">

    private static String TEMPLATE_PROJECT_DESTINATION_DIRECTORY;
    static
    {
        TEMPLATE_PROJECT_DESTINATION_DIRECTORY =
            Application.TMP + "templateProject";
    }
    private static String TEMPLATE_PROJECT_SOURCE_DIRECTORY =
            "com/nanosn/coffeemaker/templates/database/project";

    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="Private Static Methods">
    /**
     * Copies all the content of com.nanosn.coffeemaker.templates.project
     * package out of the jar, and into a folder.
     * pre: template files located at TEMPLATE_PROJECT_SOURCE_DIRECTORY
     *      exists and located in the jar
     * post: the files have been extracted to to
     *       TEMPLATE_PROJECT_DESTINATION_DIRECTORY.
     * @throws IOException
     */
    private static void CopyProjectTemplateFiles() throws IOException
    {

        Application.logger.finest("CopyProjectTemplateFiles");
        JarFile jar = new JarFile(Application.getApplicationJar());
        Application.logger.info("Jar :" + jar.getName());
        Enumeration iterator = jar.entries();

        int fileCounter = 0;
        while (iterator.hasMoreElements())
        {
            JarEntry je = (JarEntry) iterator.nextElement();
            if (je.getName().startsWith(TEMPLATE_PROJECT_SOURCE_DIRECTORY))
            {
                fileCounter++;
                String destinationPrefixRemoved =
                        je.getName().
                        substring(TEMPLATE_PROJECT_SOURCE_DIRECTORY.length());

                File dist = new File(TEMPLATE_PROJECT_DESTINATION_DIRECTORY,
                                     destinationPrefixRemoved);
                if (je.isDirectory())
                {
                    Application.logger.info("Creating directory: " +
                                            dist.getName());
                    dist.mkdirs();
                }
                else
                {
                    Application.logger.info("Creating file: " +
                                            dist.getName());
                    InputStream in =
                            new BufferedInputStream(jar.getInputStream(je));

                    OutputStream out =
                            new BufferedOutputStream(
                            new FileOutputStream(dist));

                    FileUtility.Copy(in, out);

                }
            }
        }

        if (fileCounter == 0)
        {
            Application.logger.severe("No files were found in [" +
                                      TEMPLATE_PROJECT_SOURCE_DIRECTORY +
                                      "] package directory.");
            System.exit(1);
        }
        else
        {
            Application.logger.fine("Extracted [" + fileCounter + "] file(s).");
        }
    }

    private static Map CollectFMPPdata(String applicationName) throws Exception
    {
        /*
         *  "
        +- ProjectName
        |
        +- Package: the package name of entity classes.
        |
        +- PackageDirectory
        |
        +- Classes:
        |    |
        |    +- name: The name of the class.
        |    |
        |    +- fields: the fields in the class. Also this shuld contain:
        |        |
        |        +- name
        |        |
        |        +- type
         *  |
         *  +- PersistenceUnitName
         *  |
         *  +- SchemaPersistenceUnitName
         *  |
         *  +- ConnectionString
         *  |
         *  +- UserName
         *  |
         *  +- Password
         *  |
         *  +- JDBCdriver
         */
        
        List<Map> models = Models.getModels(applicationName);
        String pkg = Settings.getPackagePrefix() + applicationName;
        @SuppressWarnings("unchecked")
        Map<String, Object> data = new HashMap(9);
        data.put("Package", pkg);
        data.put("PackageDirectory", pkg.replace(".", File.separator));
        data.put("Classes", models);
        
        //Constants for now
        data.put("PersistenceUnitName", applicationName + "PU");
        data.put("ProjectName", applicationName);
        data.put("ConnectionString", Settings.getDatabaseConnectionString());
        data.put("UserName", Settings.getDatabaseUserName());
        data.put("Password", Settings.getDatabasePassword());
        data.put("JDBCdriver", "com.mysql.jdbc.Driver");


        return data;
    }

    // </editor-fold>

    /**
     * Processes the template files for the database project.
     * Pre: User has defined entity structure.
     * Post: The application files has been generated and ready for compiling,
     *       testing.
     * @param applicationName
     * @throws Exception
     */
    public static void GenerateProject(String applicationName) throws Exception
    {
        CopyProjectTemplateFiles();

        //Create the project directory structure
        FMPP.RunFMPP(TEMPLATE_PROJECT_DESTINATION_DIRECTORY,
                     Application.GENERATED_FILES_DIRECTORY +
            File.separator + applicationName + File.separator,
                     CollectFMPPdata(applicationName));

    }
}
